package dk.fuddi.grails

import grails.converters.JSON
import grails.converters.XML
import org.codehaus.groovy.grails.commons.ConfigurationHolder

class EarthquakeController {

  // the delete, save and update actions only accept POST requests
  static allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']

  static navigation = [
      group: 'tabs',
      order: 10,
      title: 'Earthquakes',
      action: 'index'
  ]

  def index = { redirect(action: list, params: params) }

  def earthquakeService
  def exportService //Export service provided by the Export plugin

  def list = {
    params.max = Math.min(params.max ? params.max.toInteger() : 10, 100)
    params.sort = params.sort ? params.sort : "updated"
    params.order = params.order ? params.order : "desc"
    def earthquakes
    def total

    if(params.flotSeriesName != null) {
      earthquakes = findAllBetweenMag(params.flotSeriesName)
      total = earthquakes.size()
    } else {
      earthquakes = Earthquake.list(params)
      total = Earthquake.count()
    }

    if (params.type != null) {
      return getFormat(earthquakes, total, params.type)
    }

    if (params?.format && params.format != "html") {
      response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
      response.setHeader("Content-disposition", "attachment; filename=earthquakes.${params.extension}")
      exportService.export(params.format, response.outputStream, Earthquake.list(), [:], [:])
    }

    [earthquakeInstanceList: earthquakes, earthquakeInstanceTotal: total, latestFetchEarthquakes: earthquakeService.latestFetchEarthquakes,
        flotJSONDataList: earthquakeService.getFlotJSONDataList()]
  }

  def findAllBetweenMag(String flotSeriesName) {
    flash['message'] = "Sort by [$flotSeriesName]"
    def fsn = earthquakeService.flotSeriesNameMap.get(flotSeriesName)
    Earthquake.findAll("SELECT e FROM Earthquake AS e WHERE e.magnitude >= :minMag and e.magnitude <= :maxMag",
        [minMag: fsn.minMag, maxMag: fsn.maxMag])
  }
  
  def getFormat(List<Earthquake> earthquakes, long total, String type) {
    HashMap jsonMap = new HashMap()
    jsonMap.total = total
    jsonMap.earthquakes = earthquakes.collect {eq ->
      [id: eq.id, name: eq.name, title: eq.title, lat: eq.lat, lng: eq.lng, magnitude: eq.magnitude, updated: eq.updated]
    }
    if (type.equalsIgnoreCase("json")) {
      render jsonMap as JSON
      return
    }
    else if (type.equalsIgnoreCase("xml")) {
      render jsonMap as XML
      return
    }

    log.error "Could not handle type [$type]"
  }

  def show = {
    def earthquakeInstance = Earthquake.get(params.id)

    if (!earthquakeInstance) {
      flash.message = "Earthquake not found with id ${params.id}"
      redirect(action: list)
    }
    else { return [earthquakeInstance: earthquakeInstance] }
  }

  def delete = {
    Earthquake.withTransaction {
      def earthquakeInstance = Earthquake.get(params.id)
      if (earthquakeInstance) {
        try {
          earthquakeInstance.delete(flush: true)
          flash.message = "Earthquake ${params.id} deleted"
          redirect(action: list)
        }
        catch (org.springframework.dao.DataIntegrityViolationException e) {
          flash.message = "Earthquake ${params.id} could not be deleted"
          redirect(action: show, id: params.id)
        }
      }
      else {
        flash.message = "Earthquake not found with id ${params.id}"
        redirect(action: list)
      }
    }
  }

  def edit = {
    def earthquakeInstance = Earthquake.get(params.id)

    if (!earthquakeInstance) {
      flash.message = "Earthquake not found with id ${params.id}"
      redirect(action: list)
    }
    else {
      return [earthquakeInstance: earthquakeInstance]
    }
  }

  def update = {
    Earthquake.withTransaction {
      def earthquakeInstance = Earthquake.get(params.id)
      if (earthquakeInstance) {
        if (params.version) {
          def version = params.version.toLong()
          if (earthquakeInstance.version > version) {

            earthquakeInstance.errors.rejectValue("version", "earthquake.optimistic.locking.failure", "Another user has updated this Earthquake while you were editing.")
            render(view: 'edit', model: [earthquakeInstance: earthquakeInstance])
            return
          }
        }
        earthquakeInstance.properties = params
        if (!earthquakeInstance.hasErrors() && earthquakeInstance.save()) {
          flash.message = "Earthquake ${params.id} updated"
          redirect(action: show, id: earthquakeInstance.id)
        }
        else {
          render(view: 'edit', model: [earthquakeInstance: earthquakeInstance])
        }
      }
      else {
        flash.message = "Earthquake not found with id ${params.id}"
        redirect(action: list)
      }
    }
  }

  def create = {
    def earthquakeInstance = new Earthquake()
    earthquakeInstance.properties = params
    return ['earthquakeInstance': earthquakeInstance]
  }

  def save = {
    def earthquakeInstance = new Earthquake(params)
    Earthquake.withTransaction {
      if (earthquakeInstance.save(flush: true)) {
        flash.message = "Earthquake ${earthquakeInstance.id} created"
        redirect(action: show, id: earthquakeInstance.id)
      }
      else {
        render(view: 'create', model: [earthquakeInstance: earthquakeInstance])
      }
    }
  }

  def refreshEarthquakes = {
    def eqList = earthquakeService.getEarthquakes()
    int savedEarthquakes = 0
    for (eq in eqList) {
      Earthquake.withTransaction {
        def savedEq = Earthquake.findWhere(name: eq.name)
        if (savedEq == null) {
          log.debug "Save new earthquake with name $eq.name"
          eq.save()
          savedEarthquakes++
        }
      }
    }

    if (savedEarthquakes > 0) { //new earthquakes?
      earthquakeService.updateFlotJSONData() //update flot JSON data
    }

    render(view: 'refreshEarthquakes', model: [savedEarthquakes: savedEarthquakes])
  }

  def changeTimeZone = {
    if(params.myTimeZone != null) {
      session.myTimeZone = params.myTimeZone
//      println session.myTimeZone
    }
    redirect(action: list)
  }
  
}
